Skip to main content

Hosted Editors

Google Docs and Word for the web don't render text the way an ordinary page does, so the normal pipeline can't read them. Each has a dedicated adapter in content/adapters/.

These adapters are part of the extension only. They are not in the embed widget bundle, because the widget is loaded by site owners onto their own sites, not into Google's or Microsoft's.

Google Docs

Google Docs draws the document to a <canvas>. There are no text nodes to extract and nothing to highlight in place.

The adapter instead fetches the document's plain text from the session-authenticated export endpoint:

https://docs.google.com/document/d/{id}/export?format=txt

The text is then shown in the Web Reader's own reader view — a floating scrollable pane made of DOM the extension owns — where the ordinary span highlighter works safely.

Two details worth knowing:

  • The fetch has to run in the background script. The export endpoint redirects to *.googleusercontent.com, which sends no CORS headers, so a fetch from the page context fails. The background script is exempt via host permissions.
  • Documents with tabs read only the open tab. The active tab id comes from the page URL (?tab=t.<id>) and is passed to the export endpoint.

It fails soft. If the user is signed out, or the document owner has disabled export, the panel shows an error rather than appearing broken.

Word for the web

Word for the web is real DOM, but it lives in an iframe on officeapps.live.com. The manifests inject the content scripts there with all_frames: true, and the top frame hosting the editor hides its own panel so only one appears.

AspectBehaviour
Extractionp.Paragraph elements, falling back to .OutlineElement.
HighlightingOverlay only — rectangles drawn in a separate layer, never spans injected into the doc.
EditingAny beforeinput or input event pauses playback.
Long documentsWord virtualises pages. Only rendered pages can be read.

Highlighting is overlay-only here for the same reason editable regions are skipped everywhere else: injecting spans into a live editor risks the editor folding them into the saved document.

The two highlighting backends

BackendFileUsed for
Span highlightercontent/highlighter.jsOrdinary pages, and the reader view.
Overlay highlightercontent/overlay-highlighter.jsLive editor frames, where the DOM must not be touched.

The overlay backend draws sentence and word rectangles in a fixed pointer-events: none layer, positioned from Range.getClientRects(). WebReaderHighlighter.setOverlayMode(true) switches all highlight calls over to it.

Adding another editor

An adapter needs isMatch(), a way to get text, and a decision about which highlighting backend to use. Look at content/adapters/word-online.js for the in-place case and google-docs.js for the reader-view case.

Whichever you add, remember to register it in all three manifests and — if it should also ship in the widget — in the FILES array in embed/build.js.

Last updated 2026-07-22